//
// Created by 86155 on 2025/4/15.
//

#include "llvm/MC/TargetRegistry.h"
#include "Fe.h"
#include "FeTargetMachine.h"
#include "TargetInfo/FeTargetInfo.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "FeDataCtrl.h"

using namespace llvm;
/*
 * llc的目标后端都必须实现各自的void LLVMInitializeXXXTarget()函数。否则，编译目标后端Fe时会报错undefined reference to 'LLVMInitializeFeTarget'。
 * */
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeFeTarget() {
  //注册一个TargetMachine
  RegisterTargetMachine<FeTargetMachine> X(getFeTarget());
  auto *PR = PassRegistry::getPassRegistry();
  initializeFeDAGToDAGISelLegacyPass(*PR);
}

//设置堆栈以及寄存器的一些信息
StringRef computeDataLayout(const Triple &TT,const TargetOptions &options) {
  assert(TT.isArch32Bit() && "Only 32bit is currently supported!");
  return "e-m:e-p:32:32-i64:64-n32-S128";
}

//重定位模型  描述目标代码(.o)的符号链接模型
Reloc::Model getEffectiveRelocModel(const Triple &TT,std::optional<Reloc::Model> RM) {
  return RM.value_or(Reloc::Static);   //表示不可重定位目标代码，静态链接
}

//FeTargetMachine构造函数
FeTargetMachine::FeTargetMachine(const Target &T, const Triple &TT,
                                   StringRef CPU, StringRef FS,
                                   const TargetOptions &Options,
                                   std::optional<Reloc::Model> RM,
                                   std::optional<CodeModel::Model> CM,
                                   CodeGenOptLevel OL, bool JIT)
    : LLVMTargetMachine(T, computeDataLayout(TT,Options), TT, CPU, FS, Options,
                        getEffectiveRelocModel(TT,RM),
                        getEffectiveCodeModel(CM, CodeModel::Small)/*代码模型  支持一个数据段一个代码段，所有的数据和代码紧挨着*/
                        , OL),
      TLOF(std::make_unique<TargetLoweringObjectFileELF>()),
      Subtarget(TT, CPU, FS, *this)
{
  initAsmInfo();
}

namespace {
class FePassConfig : public TargetPassConfig {
public:
  FePassConfig(FeTargetMachine &TM, PassManagerBase &PM)
      : TargetPassConfig(TM, PM) {}

  FeTargetMachine &getFeTargetMachine() const {
    return getTM<FeTargetMachine>();
  }

  const FeSubtarget &getFeSubtarget() const {
    return *getFeTargetMachine().getSubtargetImpl();
  }

  bool addInstSelector() override;  /*指令选择pass*/
};
} // namespace


TargetPassConfig *FeTargetMachine::createPassConfig(PassManagerBase &PM) {
  return new FePassConfig(*this, PM);
}

bool FePassConfig::addInstSelector() {
  // Install an instruction selector.
  dataCtrl.setData();
  addPass(createFeISelDag(getFeTargetMachine()));           //createFeISelDag函数返回实际上是SelectionDAGISel的子类
  return false;
}